package top.hudk.type;

import java.util.HashMap;
import java.util.Map;

/**
 * 作用：
 *
 * @author hudk
 * @date 2020/5/26 17:02
 */
public class LRUCache<K, V> {

    private int max = 10;

    private Map<K, Node> map = new HashMap<>();

    private Node<K, V> tail;

    private Node<K, V> head;

    public V put(K key, V value) {
        if (map.size() == 10) {
            deleteHead();
        }
        if(map.size() == 0){
            this.head = new Node<>(key,value,null,null);
            this.tail = this.head;
            map.put(key,this.head);
            System.out.println(toString());
            return value;
        }
        if (map.containsKey(key)) {
            setLast(key, value);
        } else {
            linkLast(key, value);
        }
        System.out.println(toString());
        return value;
    }

    public V get(K key) {
        if (map.containsKey(key)) {
            setLast(key, null);
            System.out.println(toString());
            return this.tail.item;
        } else {
            System.out.println(toString());
            return null;
        }
    }

    /**
     * 将新的元素，放到链表尾部，并加入到中
     *
     * @param key
     * @param value
     */
    private void linkLast(K key, V value) {
        Node<K, V> tail = this.tail;
        Node<K, V> newNode = new Node<>(key, value,null, this.tail);
        this.tail = newNode;
        if (tail == null) {
            this.head = newNode;
        } else {
            tail.next = newNode;
        }
        map.put(key, newNode);
    }

    private void deleteHead() {
        if (this.head != null && this.head.next != null) {
            Node<K, V> next = this.head.next;
            this.head.next.prev = null;
            this.head.next = null;
            map.remove(this.head.kay);
            this.head.kay = null;
            this.head.item = null;
            this.head = next;
        }
    }


    /**
     * 将集合中已有的指定元素，放到尾部
     *
     * @param key
     * @param value
     */
    private V setLast(K key, V value) {
        Node<K, V> node = map.get(key);
        if (node.next != null && node.prev != null) {
            node.prev.next = node.next;
            node.next.prev = node.prev;
        }
        if (node == this.head) {
            node.next.prev = null;
            this.head = node.next;
        }
        if (node == this.tail) {
            return this.tail.item;
        }
        this.tail.next = node;
        node.prev = tail;
        node.next = null;
        this.tail = node;
        if (value != null) {
            this.tail.item = value;
        }
        return this.tail.item;
    }

    @Override
    public String toString() {
        StringBuilder stringBuilder = new StringBuilder();
        Node n = this.head;
        while (n != null) {
            stringBuilder.append(n.item.toString() + ",");
            if (n == this.tail) {
                break;
            }
            n = n.next;
        }
        return stringBuilder.toString();
    }


    private static class Node<K, V> {
        K kay;
        V item;
        LRUCache.Node<K, V> next;
        LRUCache.Node<K, V> prev;

        Node(K kay, V element, LRUCache.Node<K, V> next, LRUCache.Node<K, V> prev) {
            this.kay = kay;
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
}
